springboot项目中的定时

您所在的位置:网站首页 spring schedule 多线程 springboot项目中的定时

springboot项目中的定时

2023-06-08 14:30| 来源: 网络整理| 查看: 265

Spring 3.0 版本之后自带定时任务,提供了@EnableScheduling注解和@Scheduled注解来实现定时任务功能。

使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式:

基于注解(@Scheduled)基于注解设定多线程定时任务基于接口(SchedulingConfigurer) 在实际使用中我们如果从数据库中读取指定时间来动态执行定时任务时,就可以使用基于接口的定时任务。 一、基于注解

1.  @Scheduled注解和@EnableScheduling注解的使用

注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

@EnableScheduling注解: 在配置类上使用(或者在启动类上使用)

      作用:@EnableScheduling是一个Spring框架的注解,用于启用定时任务的支持,该注解会扫描所有标注了@Scheduled注解的方法,并在指定的时间执行这些方法。

@Scheduled注解: 来声明这是一个任务,包括 cron,fixDelay,fixRate 等类型(方法上,需先开启计划任务的支持)。

@Component 注解:是 Spring 框架中的一个核心注解,用于标识某个类是 Spring 管理的组件。被 @Component 注解标识的类会被 Spring 容器自动扫描并创建实例,然后可以通过 @Autowired 或 @Resource 注解将其注入到其他类中使用。

使用代码示例:

(1)在启动类上添加注解 @EnableScheduling

(2)创建timer包,存放定时方法

(3)在定时的java文件类的上方添加注解 @EnableScheduling 和注解 @Component

(4)在需要定时的方法上添加注解 @Scheduled

@Slf4j @Component @EnableScheduling // 1.开启定时任务 @EnableAsync // 2.开启多线程 public class InformationTimer { @Async //将一个同步方法转换为异步方法(多线程) @Scheduled(cron= "0/5 * * * * ? ") //每5秒执行一次 public void testTimer1(){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式 System.out.println("定时任务测试 1 : " + df.format(new Date())); } @Async //将一个同步方法转换为异步方法(多线程) @Scheduled(cron= "0/10 * * * * ? ") //每10秒执行一次 public void testTimer2(){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式 System.out.println("定时任务测试 2 : " + df.format(new Date())); } } 二、基于注解设定多线程的定时任务

1.多线程注解定时器步骤:(代码示例见上方)

(1)在启动类上添加注解 @EnableScheduling

(2)创建timer包,存放定时方法

(3)在定时的java文件类的上方添加注解 @EnableScheduling 和注解 @Component  和注解 @EnableAsync 

(4)在需要定时的方法上添加注解 @Scheduled 和注解 @Async(非常重要)

@EnableAsync: 

        注解是 Spring 框架中的一个注解,用于启用 Spring 异步执行功能。在 Spring 中,我们可以使用 @Async 注解来标识某个方法需要异步执行,而 @EnableAsync 注解则是用来启用这个异步执行功能的。

        使用 @EnableAsync 注解需要注意以下几点:

@EnableAsync 注解需要放置在配置类上,即带有 @Configuration 注解的类上。在配置类上添加 @EnableAsync 注解后,需要在异步方法上添加 @Async 注解才能使方法异步执行。如果要使用线程池,需要在配置类中定义一个 Executor 类型的 bean,并在 @Async 注解中指定使用的线程池。 三、基于接口设置定时任务(动态 SchedulingConfigurer)

1、创建数据表

        在MySQL数据库中创建 cron 表,并添加数据。

DROP TABLE IF EXISTS cron; CREATE TABLE cron ( cron_id VARCHAR(30) NOT NULL PRIMARY KEY, cron VARCHAR(30) NOT NULL ); INSERT INTO cron VALUES ('1', '0/5 * * * * ?');

        数据库表如下图所示:

 2、添加pom.xml配置依赖信息

        在pom.xml配置文件中添加MyBatis、 MySQL的JDBC数据库驱动依赖。

org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3 mysql mysql-connector-java 8.0.20

3、在application.yml文件中配置相关信息

        数据源,MyBatis配置等

4、创建定时器

        数据库准备好数据之后,编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。具体代码如下:

import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.support.CronTrigger; import org.springframework.util.StringUtils; import java.time.LocalDateTime; /** * 动态定时任务配置类 * @author pan_junbiao **/ @Configuration //1.主要用于标记配置类,兼备Component的效果 @EnableScheduling //2.开启定时任务 public class DynamicScheduleConfigurer implements SchedulingConfigurer{ /** * 基于注解的方式,在数据库中查询 cron **/ @Mapper public interface CronMapper { @Select("select cron from cron limit 1") public String getCron(); } //注入mapper @Autowired @SuppressWarnings("all") CronMapper cronMapper; /** * 执行定时任务. */ @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar){ taskRegistrar.addTriggerTask( //1.添加任务内容(Runnable) () -> System.out.println("当前时间:" + LocalDateTime.now().toLocalTime()), //2.设置执行周期(Trigger) triggerContext -> { //2.1 从数据库获取执行周期 String cron = cronMapper.getCron(); //2.2 合法性校验. if (StringUtils.isEmpty(cron)) { // Omitted Code .. } //2.3 返回执行周期(Date) return new CronTrigger(cron).nextExecutionTime(triggerContext); } ); } }

5、注意:

         如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。

四、@Scheduled注解各参数讲解(8个) 1、cron

        该参数接收一个cron表达式,cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个域,每一个域代表一个含义。

        cron格式:[秒] [分] [小时] [日] [月] [周] [年]

序号说明是否必填允许填写的值允许的通配符1秒是0-59, - * /2分是0-59, - * /3小时是0-23, - * /4日是1-31, - * ? / L W5月是1-12 or JAN-DEC, - * /6周是1-7 or SUN-SAT, - * ? / L #7年否empty 或 1970-2099, - * /

通配符说明:

* 表示所有值. 例如:在分的字段上设置 "*",表示每一分钟都会触发。

? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10 * ?

- 表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。

, 表示指定多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发

/ 用于递增触发。如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)。在月字段上设置'1/3'所示每月1号开始,每隔三天触发一次。

L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于"7"或"SAT"。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示“本月最后一个星期五"

W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-")

小提示:'L'和 'W'可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资) 。

# 序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六.注意如果指定"#5",正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)

小提示:周字段的设置,若使用英文字母是不区分大小写的 MON 与mon相同。

可通过在线生成Cron表达式的工具:在线Cron表达式生成器 来生成自己想要的表达式。

常用示例:

0 0 12 * * ?每天12点触发0 15 10 ? * *每天10点15分触发0 15 10 * * ?每天10点15分触发0 15 10 * * ? *每天10点15分触发0 15 10 * * ? 20052005年每天10点15分触发0 * 14 * * ?每天下午的 2点到2点59分每分触发0 0/5 14 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)0 0/5 14,18 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)每天下午的 18点到18点59分(整点开始,每隔5分触发)0 0-5 14 * * ?每天下午的 2点到2点05分每分触发0 10,44 14 ? 3 WED3月分每周三下午的 2点10分和2点44分触发0 15 10 ? * MON-FRI从周一到周五每天上午的10点15分触发0 15 10 15 * ?每月15号上午10点15分触发0 15 10 L * ?每月最后一天的10点15分触发0 15 10 ? * 6L每月最后一周的星期五的10点15分触发0 15 10 ? * 6L 2002-2005从2002年到2005年每月最后一周的星期五的10点15分触发0 15 10 ? * 6#3每月的第三周的星期五开始触发0 0 12 1/5 * ?每月的第一个中午开始每隔5天触发一次0 11 11 11 11 ?每年的11月11号 11点11分触发(光棍节)

cron表达式使用占位符:         配置文件:

time: cron: */5 * * * * * interval: 5

        每5秒执行一次:

@Scheduled(cron="${time.cron}") void testPlaceholder1() { System.out.println("Execute at " + System.currentTimeMillis()); } @Scheduled(cron="*/${time.interval} * * * * *") void testPlaceholder2() { System.out.println("Execute at " + System.currentTimeMillis()); } 2、 zone (时区)

        时区,接收一个 java.util.TimeZone#ID。cron表达式会基于该时区解析。默认是一个空字符串,即取服务器所在地的时区。比如我们一般使用的时区Asia/Shanghai。该字段我们一般留空。

3、fixedDelay (延后执行)

上一次执行完毕时间点之后多长时间再执行。如:

@Scheduled(fixedDelay = 5000) //上一次执行完毕时间点之后5秒再执行 4、fixedDelayString (延后执行,支持占位符)

        与 fixedDelay 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。如:

@Scheduled(fixedDelayString = "5000") //上一次执行完毕时间点之后5秒再执行

        占位符的使用:

                在 application.yml 配置文件中添加如下配置:

time: fixedDelay: 5000

        编写相关代码:

/** * 定时任务的使用 * @author pan_junbiao **/ @Component public class Task { @Scheduled(fixedDelayString = "${time.fixedDelay}") void testFixedDelayString() { System.out.println("定时器测试,当前时间: " + System.currentTimeMillis()); } } 5、fixedRate    

        上一次开始执行时间点之后多长时间再执行。如:

@Scheduled(fixedRate = 5000) //上一次开始执行时间点之后5秒再执行 6、fixedRateString

        与  fixedRate 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。

7、initialDelay

        第一次延迟多长时间后再执行。如:

@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次 8、initialDelayString

        与 initialDelay 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3